#ifndef __imagestorageh_
#define __imagestorageh_

// imageStorage.h
//// Image class storage

#include "geometry.h"
#include "exception.h"
#include "allocTmpl.h"
#include "lock.h"

namespace simple{
    //
    // ImageStorageBase
    //
    // ImageStorageBase is the base class for all image storage. 
    // The base object knows little more than the boundary, the
    // enclosing rectangle, which represents the image. The
    // actual image storage is left to derived classes.
    // 实际的内存分配交给继承类处理。

    class ImageStorageBase
    {
    public:
        ImageStorageBase ();
        ImageStorageBase (const Rect& boundary);

        virtual ~ImageStorageBase ();

        const Rect& boundary () const { return _boundary;}

        int  x0             () const { return _boundary.x0();}
        int  y0             () const { return _boundary.y0();}
        int  x1             () const { return _boundary.x1();}
        int  y1             () const { return _boundary.y1();}
        unsigned int width  () const { return _boundary.width();}
        unsigned int height () const { return _boundary.height();}

      // Default copy constructor and assignment operators ok.
    protected:
        Rect _boundary;
    };

    //
    // RectImageStorage
    //
    // RectImageStorage is an intermediate class for all image
    // storage objects which allocate a rectangular block of memory.
    // This is the most common storage class.  Memory is allocated
    // as a number of Bytes (i.e. unsigned char) and later cast to 
    // the propriate type.
    //
    // Memory is aligned at specific boundaries for each row in the
    // image. This allows image processing functions, especially 
    // those written for a specific platform, to take advantage of
    // this alignment.
    // 它不是一个模版类，反而，它基于每个象素的存储字节数和
    // 图像中每一行的所需内存排列来分配存储空间。

    class RectImageStorage : public ImageStorageBase
    {
    public:
        enum eAlignment {eNoAlign=0, eWordAlign=2, eDoubleWordAlign=4, eQuadWordAlign=8,
                         e2ByteAlign=2, e4ByteAlign=4, e8ByteAlign=8, e16ByteAlign=16};
        // Memory alignment for each row in the image

        RectImageStorage ();
        RectImageStorage (const Rect& boundary, unsigned int bytesPerPixel,
                          eAlignment align);

        RectImageStorage            (const RectImageStorage& src);
        RectImageStorage& operator= (const RectImageStorage& src);
        // We need our own copy constructor and assignment operator.

        virtual ~RectImageStorage ();

        bool isNull () const { return _storage.isNull();}
        // Returns true if this is a null image.

        int ref () const { return _storage.ref();}
        // Returns reference count for our storage object (for testing)

        bool lockState     () const { return _lock.lock();}
        bool unlockState   () const { return _lock.unlock();}
        // Lock/unlock our image state, but not the storage

        bool lockStorage   () const { return _storage.lockStorage ();}
        bool unlockStorage () const { return _storage.unlockStorage ();}
        // Lock/unlock our image storage

        bool lock   () const { return lockState() && lockStorage();}
        bool unlock () const { return unlockState() && unlockStorage();}
        // Lock/unlock our image state and storage

        int xoffset       () const { return _xoffset;}
        int yoffset       () const { return _yoffset;}
        // 偏移量，基于内存坐标。使用时通过与边界boundary的运算就可以得到相对的偏移
        // 此偏移量会在boundary修改时，相应的修改。

        int bytesPerPixel () const { return _bytesPerPixel;}
        int rowSpacing    () const { return _rowSpacing;}

        eAlignment alignment () const { return _align;}

        bool operator== (const RectImageStorage& src) const
        { return _storage.data() == src._storage.data();}
        bool operator!= (const RectImageStorage& src) const
        { return _storage.data() != src._storage.data();}
        // These objects are equal if they share the same underlying memory

        bool window (const Rect& window);
        // Intersect the window with our image to adjust its size. The
        // underlying pixel data is left unchanged.

        const Pel8* _rowAddress (int y) const;
        Pel8*       _rowAddress (int y);
        // Returns a pointer to the first pixel in the specified row
        // Throws BoundsException it the argument is not in range

        const Pel8* getAddr (int x, int y) const;
        Pel8*       getAddr (int x, int y);
        // Returns a pointer to specified pixel.
        // Throws BoundsException it the argument is not in range

        void rebase ();
        // Sets the image origin to (0,0) and copies the underlying storage if it
        // is shared by anyone. This function can simply multi-step operations because
        // image coordinates are easier to manipulate.

    protected:

        const Pel8* getPixel (int x, int y) const;
        void        setPixel (int x, int y, const Pel8* pixel);
        // Get/set a single pixel
        // Throws BoundsException it the argument is not in range

        void init ();
        // re-init the object as a null image

        mutable Lock   _lock;          // Access control
        Alloc<Pel8>    _storage;       // Pixel storage
        Pel8*          _begin;         // Pointer to first row
        Pel8*          _end;           // Pointer past last row,不指向有效行
        eAlignment     _align;         // Alignment
        unsigned int   _yoffset;       // Row offset to first row
        unsigned int   _xoffset;       // Pixel offset in first row
        unsigned int   _bytesPerPixel; // Bytes per pixel
        unsigned int   _rowSpacing;    // Number of bytes between rows
    };




    //
    // RectImageStorageLocker
    //
    // Locking is an important issue in multi-threaded designs. This
    // object will lock/unlock an RectImageStorage object. Using a 
    // temporary instance of RectImageLocker means that the object
    // is unlocked should an exception ever be thrown.

    class RectImageStorageLocker
    {
    public:
        RectImageStorageLocker (const RectImageStorage& image)
            : _image (image) { _image.lockState();}
        ~RectImageStorageLocker () { _image.unlockState();}
    private:
        const RectImageStorage& _image;

        // No copy or assignment is allowed
        RectImageStorageLocker (const RectImageStorageLocker&);
        RectImageStorageLocker& operator= (const RectImageStorageLocker&);
    };

}

#endif // __imagestorageh_
